﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace MagickConverter
{
    public class MagickQueue
    {
        private readonly Queue<MagickTask> _tasks = new Queue<MagickTask>();
        private readonly object _lock = new object();
        private bool Enabled { get; set; } = true;

        private int _queuedTasksCount;
        private int _completedTasksCount;

        public QueueStatus CurrrentStatus { get; set; } = QueueStatus.NoTasks;

        public event Action<int, int> QueueFinishedEvent;

        public event EventHandler QueuePausedEvent;

        public void Play()
        {
            if (Enabled || CurrrentStatus != QueueStatus.Paused)
                return;
            Enabled = true;
            NextTask();
        }

        public void GracefullyPause()
        {
            if (!Enabled || CurrrentStatus != QueueStatus.Running)
                return;
            Enabled = false;
        }

        public void EnqueueTask(MagickTask task)
        {
            lock (_lock)
            {
                task.NextTaskEvent += new Action(NextTask);
                task.NextTaskEvent += new Action(OnTaskCompleted);
                _tasks.Enqueue(task);
                ++_queuedTasksCount;
            }
            if (!Enabled || CurrrentStatus != QueueStatus.NoTasks)
                return;
            NextTask();
        }

        public void EnqueueMultiple(IEnumerable<MagickTask> tasks)
        {
            lock (_lock)
            {
                foreach (MagickTask task in tasks)
                {
                    task.NextTaskEvent += new Action(NextTask);
                    task.NextTaskEvent += new Action(OnTaskCompleted);
                    _tasks.Enqueue(task);
                    ++_queuedTasksCount;
                }
                if (!Enabled || CurrrentStatus != QueueStatus.NoTasks)
                    return;
                NextTask();
            }
        }

        private void NextTask()
        {
            if (Enabled)
            {
                MagickTask task;
                lock (_lock)
                {
                    if (!_tasks.Any())
                    {
                        NotifyQueueFinished();
                        return;
                    }
                    task = _tasks.Dequeue();
                    if (task == null)
                        return;
                }
                if (task != null)
                {
                    CurrrentStatus = QueueStatus.Running;
                    task.Convert();
                }
                else
                    NotifyQueuePaused();
            }
            else
                NotifyQueuePaused();
        }

        private void OnTaskCompleted()
        {
            ++_completedTasksCount;
        }

        private void NotifyQueueFinished()
        {
            Console.WriteLine("MagickQueue: all tasks completed.");
            CurrrentStatus = QueueStatus.NoTasks;
            if (QueueFinishedEvent == null) return;
            QueueFinishedEvent(_queuedTasksCount, _completedTasksCount);
        }

        private void NotifyQueuePaused()
        {
            Console.WriteLine("MagickQueue: tasks has been paused...");
            CurrrentStatus = QueueStatus.Paused;
            if (QueuePausedEvent == null) return;
            QueuePausedEvent(this, EventArgs.Empty);
        }
    }
}
